/*
 * Copyright 2010 Christoph Widulle (christoph.widulle@googlemail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */



package com.android1.amarena2d.nodes.behavior.delegates;

import com.android1.amarena2d.actions.base.Action;
import com.android1.amarena2d.actions.base.Animate;
import com.android1.amarena2d.actions.base.Repeat;
import com.android1.amarena2d.actions.base.RepeatForever;
import com.android1.amarena2d.animation.Animation;
import com.android1.amarena2d.animation.AnimationPlayer;
import com.android1.amarena2d.commons.Callback;
import com.android1.amarena2d.engine.EngineObject;
import com.android1.amarena2d.engine.TargetActionsStore;
import com.android1.amarena2d.nodes.behavior.ActionTarget;

/**
 * Convinient helper for Sprites to handle animations.
 */
public abstract class AbstractAnimationDelegate extends EngineObject implements AnimationDelegate, AnimationPlayer, AnimationPlayer.Options, AnimationPlayer.RepeatOptions {

    protected Animation.Frame currentFrame;

    //Actions that we keep beside a pool. Makes sure we don't break the pooling concept.
    protected Animate animateAction;
    protected RepeatForever repeatForeverAction;
    protected Repeat repeatAction;

    protected Action activeAction;
    protected Animation defaultAnimation;
    protected Animation activeAnimation;
    protected final TargetActionsStore targetActionsStore;

    //temp. player member
    protected int repeattimes;
    protected Animation animation;
    protected boolean repeatForever;
    protected boolean restoreOriginalFrame;
    protected Callback<ActionTarget> onFinishedCallback;

    public AbstractAnimationDelegate(AnimatedActionTarget parent) {
        this.targetActionsStore = engine.getActionManager().register(parent);
    }


    @Override
    public boolean isRunning() {
        return activeAction != null && activeAction.isRunning();
    }

    @Override
    public boolean isRunning(Animation animation) {
        return activeAction != null && animateAction != null && animateAction.isRunning() && animateAction.getAnimation() == animation;
    }

    public void stop() {
        if (isRunning()) {
            targetActionsStore.stop(activeAction);
        }
        activeAction = null;
    }

    @Override
    public Options selectDefault() {
        if (defaultAnimation == null)
            throw new IllegalStateException("No default animation found.");
        this.animation = defaultAnimation;
        return this;
    }

    public Options select(Animation animation) {
        this.animation = animation;
        return this;
    }

    @Override
    public Options select(String name) {
        this.animation = engine.getLibrary().animationsLib().find(name);
        return this;
    }

    @Override
    public RepeatOptions repeatForever() {
        this.repeatForever = true;
        return this;
    }

    @Override
    public RepeatOptions repeat(int times) {
        this.repeattimes = times;
        this.repeatForever = false;
        return this;
    }

    @Override
    public Options restoreOriginalFrame() {
        this.restoreOriginalFrame = true;
        return this;
    }

    @Override
    public Options onFinished(Callback<ActionTarget> callback) {
        this.onFinishedCallback = callback;
        return this;
    }

    @Override
    public void play() {
        if (isRunning())
            stop();

        if (animation == null)
            animation = defaultAnimation;
        if (animation == null)
            throw new IllegalStateException("No default animation found.");

        Action action = obtainAnimate(animation, repeatForever, repeattimes, restoreOriginalFrame, onFinishedCallback);
        run(action);
        resetPlayer();
    }

    private void run(Action action) {
        activeAction = action;
        targetActionsStore.run(action);
    }


    public Animation getDefaultAnimation() {
        return defaultAnimation;
    }

    public void setDefaultAnimation(Animation defaultAnimation) {
        this.defaultAnimation = defaultAnimation;
    }

    @Override
    public Animation.Frame getCurrentFrame() {
        return currentFrame;
    }

    private void resetPlayer() {
        repeatForever = false;
        repeattimes = 0;
        restoreOriginalFrame = false;
        animation = null;
        onFinishedCallback = null;
    }


    @Override
    public void init() {
        if (defaultAnimation != null)
            defaultAnimation.init();
    }

    @Override
    public void dispose() {
        if (defaultAnimation != null)
            defaultAnimation.dispose();
    }

    @Override
    public boolean isInit() {
        if (defaultAnimation != null)
            return defaultAnimation.isInit();
        return true;
    }

    private Action obtainAnimate(Animation animation, boolean repeatForever, int repeattimes, boolean restoreOriginalFrame, Callback<ActionTarget> onFinshedCallback) {
        Action action;
        if (animateAction == null) {
            animateAction = new Animate(animation, restoreOriginalFrame);
        } else {
            animateAction.reset(animation, restoreOriginalFrame);
        }
        if (repeatForever) {

            if (repeatForeverAction == null)
                repeatForeverAction = new RepeatForever(animateAction);
            else
                repeatForeverAction.reset(animateAction);

            action = repeatForeverAction;

        } else if (repeattimes > 0) {

            if (repeatAction == null)
                repeatAction = new Repeat(repeattimes, animateAction);
            else
                repeatAction.reset(repeattimes, animateAction);

            action = repeatAction;

        } else {

            action = animateAction;
        }
        action.setOnStopCallback(onFinshedCallback);
        return action;
    }


}
